home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / Sample Code / Typography Samples / Dave’s Fab Samples ƒ / DavesFabSamples.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-10  |  16.8 KB  |  536 lines  |  [TEXT/KAHL]

  1. /******************************************************************************\
  2. *
  3. * Apple Macintosh Developer Technical Support
  4. *
  5. * Main program file
  6. *
  7. * Program: DavesFabSamples
  8. * File:    DavesFabSamples.c
  9. *
  10. * by:      Forrest Tanaka
  11. *
  12. * Copyright © 1988-1994 Apple Computer, Inc.
  13. * All rights reserved.
  14. *
  15. \******************************************************************************/
  16.  
  17.  
  18. /******************************************************************************\
  19. * Header Files
  20. \******************************************************************************/
  21.  
  22. #include <Desk.h>
  23. #include <DiskInit.h>
  24. #include <Errors.h>
  25. #include <Fonts.h>
  26. #include <Menus.h>
  27. #include <Resources.h>
  28. #include <ToolUtils.h>
  29.  
  30. #include <AppleEvents.h>
  31. #include <GestaltEqu.h>
  32. #include <Packages.h>
  33. #include <Traps.h>
  34.  
  35. #include <graphics routines.h>
  36.  
  37. #include "DavesFabSamples.h"
  38. #include "MenuHandler.h"
  39.  
  40.  
  41. /******************************************************************************\
  42. * Constants
  43. \******************************************************************************/
  44.  
  45. #define kMaxSleepTime 60 /* # ticks willing to wait between minor switches */
  46.  
  47.  
  48. /******************************************************************************\
  49. * Macros
  50. \******************************************************************************/
  51.  
  52. /* Return status of bth bit of m */
  53. #define btst(m,b) ((m) & (1L << (b)))
  54.  
  55.  
  56. /******************************************************************************\
  57. * Global Variables
  58. \******************************************************************************/
  59.  
  60. Boolean gQuitting;       /* True if user requested that this app quit */
  61. Boolean gWereInFront;    /* True if this application is frontmost */
  62. Boolean gFixMenus;       /* True if menus need fixing */
  63. Boolean gHasAppleEvents; /* True if Apple Events implemented */
  64. Boolean gHasCoolSF;      /* True if 7.0 Standard File routines available */
  65.  
  66. AEEventHandlerUPP    gOurAEQuitHandler;        // proc ptr for our event handler
  67.  
  68. #if defined(powerc) || defined(__powerc)
  69.     QDGlobals    qd;
  70. #endif
  71.  
  72.  
  73. /******************************************************************************\
  74. * Private Function Prototypes
  75. \******************************************************************************/
  76.  
  77. int main(void);
  78.  
  79. void StartUp(void);
  80.  
  81. void gxShutDown(void);
  82.  
  83. void EventLoop(void);
  84.  
  85. void DoMouseDown(
  86.     EventRecord *anEvent);
  87.  
  88. void DoKeyDown(
  89.     EventRecord *anEvent);
  90.  
  91. pascal OSErr HandleAEquit(
  92.     AppleEvent *quitAppleEvent,
  93.     AppleEvent *reply,
  94.     long       handlerRefCon);
  95.  
  96. OSErr DoneRequiredParams(
  97.     AppleEvent *anAppleEvent);
  98.  
  99. void DoWindowClose(
  100.     EventRecord *anEvent,
  101.     WindowPtr   eventWindow);
  102.     
  103. void Exception (
  104.     long msgType,
  105.     long msgCode);
  106.  
  107.  
  108.  
  109. /******************************************************************************\
  110. * Public: main - Entry gxPoint to this application
  111. *
  112. * After the gxHeap is initialized by allocating several master pointer blocks and
  113. * expanding the application’s gxHeap to its maximum size, StartUp is called to
  114. * complete initialization.  Then the main event loop is entered, and that’s
  115. * where we stay until the user chooses Quit.
  116. \******************************************************************************/
  117.  
  118. int main()
  119. {
  120.     MaxApplZone();                    /* Prepare the gxHeap */
  121.     MoreMasters(); MoreMasters();
  122.     MoreMasters(); MoreMasters();
  123.     MoreMasters(); MoreMasters();
  124.     MoreMasters(); MoreMasters();
  125.  
  126.     StartUp();                        /* gxInitialize the application */
  127.     EventLoop();                    /* Execute the main event loop */
  128.     gxShutDown();                    /* Shut down the application */
  129.     
  130.     return 0;                        /* Return the ANSI way */
  131. }
  132.  
  133.  
  134. /******************************************************************************\
  135. * StartUp - Do whatever has to be done to gxInitialize the application
  136. *
  137. * This routine is called after the gxHeap is initialized to gxInitialize the
  138. * application.  This involves initializing the toolbox, emergency memory,
  139. * loading up the menus, validating the current environment, and initializing
  140. * global variables.  If any errors occur while doing this, StartUp displays
  141. * an alert telling the user what the error was and then ExitToShell is called.
  142. * This is an unusual way to react to errors, and I only do it here because it’s
  143. * so early in execution that there really isn’t much else that can be done.
  144. *
  145. * See EmergMem.h in this application for details about emergency memory.
  146. \******************************************************************************/
  147.  
  148. static void StartUp()
  149. {
  150.     short        result;  /* Result of alert; ignored */
  151.     long         aeAttrs; /* AppleEvent attributes */
  152.     long         sfAttrs; /* Standard File attributes */
  153.     OSErr        error;
  154.     long         msgType;
  155.     long         msgCode;
  156.  
  157.     /* gxInitialize Sarano */
  158.     GXEnterGraphics();
  159.  
  160.     /* gxInitialize the toolbox */
  161.     InitGraf( &qd.thePort );
  162.     InitFonts();
  163.     InitWindows();
  164.     InitMenus();
  165.     TEInit();
  166.     InitDialogs( nil );
  167.  
  168.     /* gxInitialize emergency memory */
  169.  
  170.     /* gxInitialize the menus */
  171.     error = StartMenus();
  172.     
  173.     if (error == memFullErr)        Exception( rMemErrMessages, kMemErrAppOpenMsg );
  174.     else if (error == resNotFound)    Exception( rResErrMessages, kResErrAppDamageMsg );
  175.     else if (error == dsSysErr)        Exception( rMiscErrMessages, kMiscErrUnknownMsg );
  176.  
  177.  
  178.     /* Check for the fancier capabilities */
  179.     
  180.     error = Gestalt( gestaltAppleEventsAttr, /*<*/&aeAttrs );
  181.     if (error != noErr)
  182.         gHasAppleEvents = false;
  183.     else
  184.         gHasAppleEvents = btst( aeAttrs, gestaltAppleEventsPresent );
  185.         
  186.     error = Gestalt( gestaltStandardFileAttr, /*<*/&sfAttrs );
  187.     if (error != noErr)
  188.         gHasCoolSF = false;
  189.     else
  190.         gHasCoolSF = btst( sfAttrs, gestaltStandardFile58 );
  191.  
  192.     /* Install the AppleEvent handler */
  193.     if (gHasAppleEvents)
  194.     {
  195.         gOurAEQuitHandler = NewAEEventHandlerProc(HandleAEquit);
  196.         
  197.         error = AEInstallEventHandler( kCoreEventClass,
  198.                                         kAEQuitApplication,
  199.                                         gOurAEQuitHandler, 0, false );
  200.                                         
  201.         if (error == memFullErr)    Exception( rMemErrMessages, kMemErrAppOpenMsg );
  202.         else if (error != noErr)    Exception( rMiscErrMessages, kMiscErrUnknownMsg );
  203.     }
  204. }
  205.  
  206.  
  207. /******************************************************************************\
  208. * gxShutDown - Do whatever has to be done to shut down the application
  209. *
  210. * This routine is called when the application is about to shut down.  It calls
  211. * GXExitGraphics to shut down Sarano graphics.
  212. \******************************************************************************/
  213.  
  214. static void gxShutDown()
  215. {
  216.     DisposeRoutineDescriptor(gOurAEQuitHandler); // dispose our routine descriptor
  217.     GXExitGraphics();
  218. }
  219.  
  220.  
  221. /******************************************************************************\
  222. * EventLoop - Main event loop for this application
  223. *
  224. * This is the main event loop of this application.  During every iteration of
  225. * the event loop, the menus are kept up-to-date.  Also, NoEmergMem is called to
  226. * detect whether the emergency memory was used.  If it was, then RecoverEmergMem
  227. * is called in an attept to get it back.  If it can’t, then some commands could
  228. * be disabled until the memory can be recovered.
  229. \******************************************************************************/
  230.  
  231. static void EventLoop()
  232. {
  233.     EventRecord anEvent;    /* An incoming event */
  234.     WindowPtr   lastWindow; /* Pointer to front window during last iteration */
  235.     WindowPtr   currWindow; /* Pointer to the current front window */
  236.  
  237.     gWereInFront = true;
  238.     gQuitting = false;
  239.     gFixMenus = true;
  240.     lastWindow = nil;
  241.     
  242.     InitCursor();
  243.  
  244.     /* We loop until gQuitting is true */
  245.     
  246.     while (!gQuitting)
  247.     {
  248.         /* Fix the menus to reflect current conditions */
  249.         currWindow = FrontWindow();
  250.         if (currWindow != lastWindow || gFixMenus)
  251.         {
  252.             FixMenus();
  253.             lastWindow = currWindow;
  254.             gFixMenus = false;
  255.         }
  256.  
  257.         /* It’s time to get and examine an event */
  258.         
  259.         if ( WaitNextEvent( everyEvent, &anEvent, kMaxSleepTime, nil ) )
  260.         {
  261.             switch (anEvent.what)
  262.             {
  263.                 case mouseDown:
  264.                     DoMouseDown( &anEvent );
  265.                     break;
  266.                     
  267.                 case keyDown:
  268.                 case autoKey:
  269.                     DoKeyDown( &anEvent );
  270.                     break;
  271.                     
  272.                 case updateEvt:
  273.                     DoUpdateEvt( &anEvent );
  274.                     break;
  275.                     
  276.                 case kHighLevelEvent:
  277.                     (void)AEProcessAppleEvent( &anEvent );
  278.                     break;
  279.             }
  280.         }
  281.     }
  282. }
  283.  
  284.  
  285. /******************************************************************************\
  286. * DoMouseDown - Mouse-down event dispatcher
  287. *
  288. * When a mouseDown event is received in the main event loop, this routine is
  289. * called to determine which area on the screens the mouseDown was, and to
  290. * dispatch to the appropriate routine to handle mouseDown events in that area.
  291. * The mouseDown event is passed in the anEvent parameter.
  292. *
  293. * See MenuHandler.h for routines that handle mouse-down events in the menu bar.
  294. \******************************************************************************/
  295.  
  296. static void DoMouseDown(
  297.     EventRecord *anEvent) /* Contains mouse-down event */
  298. {
  299.     short     clickArea;   /* Area of the screen that was clicked */
  300.     WindowPtr eventWindow; /* Pointer the clicked window, if any */
  301.  
  302.     /* Find clicked area of screen or window */
  303.     clickArea = FindWindow( anEvent->where, /*<*/&eventWindow );
  304.  
  305.     /* Jump to mouseDown-handling routine appropriate for screen area */
  306.     switch (clickArea)
  307.     {
  308.         case inMenuBar:
  309.             DoMenuChoice( MenuSelect( anEvent->where ) );
  310.             break;
  311.         case inGoAway:
  312.             DoWindowClose( anEvent, eventWindow );
  313.             break;
  314.         default:
  315.             break;
  316.     }
  317. }
  318.  
  319.  
  320. /******************************************************************************\
  321. * DoKeyDown - Key-down event dispatcher
  322. *
  323. * When a keyDown or autoKey event is received in the main event loop, this
  324. * routine is called to determine whether key is a command-key equivalent for a
  325. * menu item or not.  If the command key isn’t down, then the key stroke is
  326. * ignored.  Otherwise, MenuKey is called to get the menu ID and item number
  327. * of the menu item that corresponds to the command key, if any.  Then
  328. * DoMenuChoice is called to dispatch to the appropriate routine for the chosen
  329. * menu item.  The keyDown or autoKey event is passed in anEvent.
  330. \******************************************************************************/
  331.  
  332. static void DoKeyDown(
  333.     EventRecord *anEvent) /* Contains the key-down event */
  334. {
  335.     char theKey; /* ASCII code of key that was pressed */
  336.  
  337.     /* Get the ASCII code of the pressed key */
  338.     theKey = anEvent->message & charCodeMask;
  339.  
  340.     /* If anEvent was keyDown and command key was down, it’s menu command */
  341.     if (anEvent->what == keyDown && (anEvent->modifiers & cmdKey))
  342.         DoMenuChoice( MenuKey( theKey ) );
  343. }
  344.  
  345.  
  346. /******************************************************************************\
  347. * Private: DoWindowClose - Handle a click in the close box of a window
  348. *
  349. * This routine should be called when the user clicks in the close box of the
  350. * window specified by eventWind.  The mouse is tracked until the user releases
  351. * the mouse button.  If the user released the mouse button while the mouse was
  352. * in the close box, then DisposeWindow is called to close the window.  anEvent
  353. * contains the mouse-down event that was determined to be a mouse click in the
  354. * window.
  355. \******************************************************************************/
  356.  
  357. static void DoWindowClose(
  358.     EventRecord *anEvent,    /* Mouse-down event in the close box */
  359.     WindowPtr   eventWindow) /* Pointer to the window that was clicked */
  360. {
  361.     if (TrackGoAway( eventWindow, anEvent->where ))
  362.         DisposeWindow( eventWindow );
  363. }
  364.  
  365.  
  366. /******************************************************************************\
  367. * Private: HandleAEquit - Handler for 'quit' AppleEvent
  368. *
  369. * This is the AppleEvent handler for the 'quit' AppleEvent as passed in the
  370. * quitAppleEvent parameter by the AppleEvent Manager.  The DoQuit routine is
  371. * called which causes this application to quit at the start of the next
  372. * iteration of the main event loop.
  373. *
  374. * Though the quit AppleEvent doesn’t contain any parameters, the standard thing
  375. * to do in reaction to any AppleEvent is to check to see if there are any
  376. * required parameters in the AppleEvent that this routine doesn’t recognise.
  377. * DoneRequiredParms checks for this condition and returns an error if there are
  378. * in fact required parameters in the AppleEvent or if some other error occurs
  379. * during the check.
  380. \******************************************************************************/
  381.  
  382. static pascal OSErr HandleAEquit(
  383.     AppleEvent *quitAppleEvent, /* Contains the ‘quit’ AppleEvent */
  384.     AppleEvent *reply,          /* Returns reply; ignored */
  385.     long       handlerRefCon)   /* Application-defined parameter; ignored */
  386. {
  387. #pragma unused(reply,handlerRefCon)
  388.     OSErr error;
  389.  
  390.     /* quit AE has no parms, but check in case the client requires any */
  391.     error = DoneRequiredParams( quitAppleEvent );
  392.     
  393.     if (error == noErr)
  394.         /* No extra parameters; handle Quit command */
  395.         DoQuit();
  396.  
  397.     return error;
  398. }
  399.  
  400.  
  401. /******************************************************************************\
  402. * DoneRequiredParams - Done processing required params; OK?
  403. *
  404. * DoneRequiredParams checks to see if the AppleEvent specified by the
  405. * anAppleEvent parameter has any required parameters that we haven’t yet
  406. * processed.  If there aren’t any left, then noErr is returned.  If there are
  407. * required parameters that haven’t been processed yet, then errAEEventNotHandled
  408. * is returned.  If any other errors occur, then that error code is returned.
  409. \******************************************************************************/
  410.  
  411. static OSErr DoneRequiredParams(
  412.     AppleEvent *anAppleEvent) /* AppleEvent being checked */
  413. {
  414.     DescType typeCode;   /* Type of AppleEvent attribute found; ignored */
  415.     Size     actualSize; /* Actual size of parameters; ignored */
  416.     OSErr    error;
  417.  
  418.     /* Are there any required parameters in AppleEvent we didn’t process? */
  419.     
  420.        error = AEGetAttributePtr(
  421.                anAppleEvent,
  422.             keyMissedKeywordAttr,
  423.             typeWildCard,
  424.             &typeCode,
  425.             nil,
  426.             0,
  427.             &actualSize );
  428.             
  429.     if (error == errAEDescNotFound)
  430.         /* No required parameters left, so no error */
  431.         error = noErr;
  432.     else if (error == noErr)
  433.         /* There was at least one required parameter we didn’t process */
  434.         error = errAEEventNotHandled;
  435.  
  436.     return error;
  437. }
  438.  
  439.  
  440. /******************************************************************************\
  441. * Public: DoQuit
  442. *
  443. * Each open window is checked to see what kind it is, and then it is closed
  444. * appropriately.
  445. \******************************************************************************/
  446.  
  447. void DoQuit()
  448. {
  449.     WindowPtr aWindow; /* Pointer to each window in the window list */
  450.  
  451.     aWindow = FrontWindow();
  452.  
  453.     /* Keep closing a window until there are no windows left */
  454.     while (aWindow != nil)
  455.     {
  456.         DisposeWindow( aWindow );
  457.         aWindow = FrontWindow();
  458.     }
  459.  
  460.     /* Tell the main event loop that we’re done */
  461.     gQuitting = true;
  462. }
  463.  
  464.  
  465. /******************************************************************************\
  466. * Public: DoUpdateEvt
  467. *
  468. * As new kinds of windows are added to this application, this routine will have
  469. * to be able to detect the new kind of window and dispatch to the routine that
  470. * handles update events in that kind of window.
  471. \******************************************************************************/
  472.  
  473. void DoUpdateEvt(
  474.     EventRecord *anEvent) /* Update event */
  475. {
  476.     WindowPtr eventWindow; /* Pointer to the window to update */
  477.  
  478.     /* Get a pointer to the window that needs an update */
  479.     eventWindow = (WindowPtr)anEvent->message;
  480.  
  481.     /* Update the window that needs it */
  482.     SetPort( eventWindow );
  483.     BeginUpdate( eventWindow );
  484.     EndUpdate( eventWindow );
  485. }
  486.  
  487.  
  488. /******************************************************************************\
  489. * Public: ShowAlert
  490. *
  491. * To position the alert before it’s displayed, the ALRT resource is loaded
  492. * before it’s displayed, and its boundsRect is put into the proper position
  493. * through the CenterScreenRect routine.  Because this modifies the ALRT
  494. * resource in memory and because ALRT resources are normally purgeable, it must
  495. * be made unpurgeable until the alert is dismissed.
  496. \******************************************************************************/
  497.  
  498. short ShowAlert(
  499.     short alertType,    /* Type of alert to display */
  500.     short buttonOption, /* Button options for alert */
  501.     short messageClass, /* Class of message to display in alert */
  502.     short messageIndex) /* Index of message to display in alert */
  503. {
  504.     short        itemHit;     /* Item number of clicked item */
  505.     Str255        aMessage;
  506.  
  507.     /* Put the specified message into the dialog parameter text */
  508.     if (messageIndex != 0)
  509.     {
  510.         GetIndString( aMessage, messageClass, messageIndex );
  511.         ParamText( aMessage, "\P", "\P", "\P" );
  512.     }
  513.  
  514.     /* Show the stop alert */
  515.     InitCursor();
  516.  
  517.     /* Present the alert */
  518.     if (alertType == kGenericAlert)            itemHit = Alert( buttonOption, nil );
  519.     else if (alertType == kNoteAlert)        itemHit = NoteAlert( buttonOption, nil );
  520.     else if (alertType == kCautionAlert)    itemHit = CautionAlert( buttonOption, nil );
  521.     else if (alertType == kStopAlert)        itemHit = StopAlert( buttonOption, nil );
  522.  
  523.     return itemHit;
  524. }
  525.  
  526.  
  527. /******************************************************************************\
  528. * Exception - Signal that an exception has occured and exit
  529. \******************************************************************************/
  530.  
  531. void Exception ( long msgType, long msgCode)
  532. {
  533.     ShowAlert( kStopAlert, rOKAlertID, msgType, msgCode );
  534.     ExitToShell();
  535. }
  536.